package com.tfswx.serialport.service;

import com.alibaba.fastjson.JSON;
import com.fazecast.jSerialComm.SerialPort;
import com.tfswx.serialport.config.SerialportConfig;
import com.tfswx.serialport.socket.WebSocket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.regex.Pattern;

/**
 * @author ricky
 * @date 2021/7/19
 */
@Slf4j
@Component
public class SerialportService {
    @Resource
    private SerialportConfig config;

    private static final LinkedBlockingQueue<String> intervalCmdList = new LinkedBlockingQueue<>();
    private static final LinkedBlockingQueue<String> lightCmdList = new LinkedBlockingQueue<>();
    private static final LinkedBlockingQueue<Byte> bufList = new LinkedBlockingQueue<>();

    private SerialPort serialPort;

    @PostConstruct
    public void init() {
        String portName = config.getPortName();
        List<String> portNameList = new ArrayList<>();
        SerialPort[] commPorts = SerialPort.getCommPorts();
        boolean isOk = false;
        for (SerialPort commPort : commPorts) {
            String systemPortName = commPort.getSystemPortName();
            portNameList.add(systemPortName);
            if (systemPortName.equals(portName)) {
                isOk = true;
            }
        }
        if (!isOk) {
            throw new RuntimeException("串口配置不正确，请配置为以下内容之一：" + JSON.toJSONString(portNameList));
        }

        serialPort = SerialPort.getCommPort(portName);
        boolean b = serialPort.setComPortParameters(config.getBaudRate(), 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);
        log.info("设置：{}", b);
        serialPort.openPort();

        new receiveTask(serialPort);
        new turnOnLockTask(serialPort);
        new execTask(serialPort);
        log.info("串口已打开：{}", portName);
    }

    public void send(String cmd) {
        try {
            if (cmd.matches("L\\(\\d+,\\d+,1\\)E")) {
                intervalCmdList.put(cmd);
            } else {
                lightCmdList.put(cmd);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    private class turnOnLockTask extends Thread {
        private SerialPort serialPort;

        public turnOnLockTask(SerialPort serialPort) {
            this.serialPort = serialPort;
            start();
        }

        @Override
        public void run() {
            while (true) {
                try {
                    String cmd = intervalCmdList.poll();
                    if (cmd == null) {
                        Thread.sleep(100);
                        continue;
                    }
                    log.info("发送串口命令：{}", cmd);
                    byte[] data = cmd.getBytes();
                    int numWrite = serialPort.writeBytes(data, data.length);
                    Thread.sleep(config.getInterval());
                } catch (Exception e) {
                    log.error("命令执行异常", e);
                }
            }
        }
    }

    private class execTask extends Thread {
        private SerialPort serialPort;

        public execTask(SerialPort serialPort) {
            this.serialPort = serialPort;
            start();
        }

        @Override
        public void run() {
            while (true) {
                try {
                    String cmd = lightCmdList.poll();
                    if (cmd == null) {
                        Thread.sleep(100);
                        continue;
                    }
                    log.info("发送串口命令：{}", cmd);
                    byte[] data = cmd.getBytes();
                    int numWrite = serialPort.writeBytes(data, data.length);
                    Thread.sleep(50);
                } catch (Exception e) {
                    log.error("命令执行异常", e);
                }
            }
        }
    }

    private class receiveTask extends Thread {
        private SerialPort serialPort;

        public receiveTask(SerialPort serialPort) {
            this.serialPort = serialPort;
            start();
        }

        @Override
        public void run() {
            List<Byte> tempList = new ArrayList<>();
            while (true) {
                try {
                    if (serialPort.bytesAvailable() <= 0) {
                        Thread.sleep(100);
                        continue;
                    }
                    log.info("接收到消息");
                    byte[] newData = new byte[serialPort.bytesAvailable()];
                    int numRead = serialPort.readBytes(newData, newData.length);

                    for (byte newDatum : newData) {
                        //                            log.info("Byte值：{}", newDatum);
                        if (newDatum != 10 && newDatum != 13 && newDatum > 0) {
                            tempList.add(newDatum);
                            if (newDatum == 69) {
                                // E
                                byte[] bytes = new byte[tempList.size()];
                                for (int i = 0; i < tempList.size(); i++) {
                                    Byte aByte = tempList.get(i);
                                    bytes[i] = aByte;
                                }
                                String str = new String(bytes);
                                tempList = new ArrayList<>();

                                log.info("发送命令到前端：{}", str);
                                WebSocket.sendInfo(str);
                            }
                        }
                    }
                } catch (Exception e) {
                    log.error("消息接收异常", e);
                }
            }
        }
    }
}
